/****************************************************************************************
*                                                                                      *
*                          Projeto BioInfo - Lincs and CIn / UFPE                      *
*                                    07/10/2014                                        *
*																					   *
****************************************************************************************
* Descricao: Arquivo que contem funcoes da classe Threads.                     *
****************************************************************************************
* Responsaveis: Jefferson Ramos(jrla)													   *
*                                                                                      */
/*                                                                                     *
****************************************************************************************/
#include <Threads.hpp>

int Threads::maximum ( 
						int diag1, int diag2, int diag3, int diag4,
						int *cust_diag, int *score_up, int left,
						byte_Union *direction
						){

	if (diag1  < (left + custoIn)) //Mach ganha de insersao
	{
		if ((left + custoIn) >= (score_up[0] + custoRe)) {
			direction->bits.nc1 = 1;
			score_up[0] = (left + custoIn); //Insersao
		}
		else {
			direction->bits.nc1 = 0;
			score_up[0] = (score_up[0] + custoRe); //Remocao
		}
	}
	else //Insersao ganha do Mach
	{
		if (diag1 < (score_up[0] + custoRe)) {
			direction->bits.nc1 = 0;
			score_up[0] = (score_up[0] + custoRe); //remocao
		}
		else {
			if (cust_diag[0] == 1) {
				direction->bits.nc1 = 3;
				score_up[0] = diag1; //mach
			}
			else {
				direction->bits.nc1 = 2;
				score_up[0] = diag1; //mach
			}
		}
	}
	left = score_up[0];

	if (diag2  < (left + custoIn)) //Mach ganha de insersao
	{
		if ((left + custoIn) >= (score_up[1] + custoRe)) {
			direction->bits.nc2 = 1;
			score_up[1] = (left + custoIn); //Insersao
		}
		else {
			direction->bits.nc2 = 0;
			score_up[1] = (score_up[1] + custoRe); //Remocao
		}
	}
	else //Insersao ganha do Mach
	{
		if (diag2 < (score_up[1] + custoRe)) {
			direction->bits.nc2 = 0;
			score_up[1] = (score_up[1] + custoRe); //remocao
		}
		else {
			if (cust_diag[1] == 1) {
				direction->bits.nc2 = 3;
				score_up[1] = diag2; //mach
			}
			else {
				direction->bits.nc2 = 2;
				score_up[1] = diag2; //mach
			}
		}
	}
	left = score_up[1];

	if (diag3  < (left + custoIn)) //Mach ganha de insersao
	{
		if ((left + custoIn) >= (score_up[2] + custoRe)) {
			direction->bits.nc3 = 1;
			score_up[2] = (left + custoIn); //Insersao
		}
		else {
			direction->bits.nc3 = 0;
			score_up[2] = (score_up[2] + custoRe); //Remocao
		}
	}
	else //Insersao ganha do Mach
	{
		if (diag3 < (score_up[2] + custoRe)) {
			direction->bits.nc3 = 0;
			score_up[2] = (score_up[2] + custoRe); //remocao
		}
		else {
			if (cust_diag[2] == 1) {
				direction->bits.nc3 = 3;
				score_up[2] = diag3; //mach
			}
			else {
				direction->bits.nc3 = 2;
				score_up[2] = diag3; //mach
			}
		}
	}
	left = score_up[2];

	if (diag4  < (left + custoIn)) //Mach ganha de insersao
	{
		if ((left + custoIn) >= (score_up[3] + custoRe)) {
			direction->bits.nc4 = 1;
			score_up[3] = (left + custoIn); //Insersao
		}
		else {
			direction->bits.nc4 = 0;
			score_up[3] = (score_up[3] + custoRe); //Remocao
		}
	}
	else //Insersao ganha do Mach
	{
		if (diag4 < (score_up[3] + custoRe)) {
			direction->bits.nc4 = 0;
			score_up[3] = (score_up[3] + custoRe); //remocao
		}
		else {
			if (cust_diag[3] == 1) {
				direction->bits.nc4 = 3;
				score_up[3] = diag4; //mach
			}
			else {
				direction->bits.nc4 = 2;
				score_up[3] = diag4; //mach
			}
		}
	}
	return score_up[3];
}


void Threads::print_results()
{
	int taxa_individuals = 0;
	for(int i = 1; i <= num_individuals*alignment_by_individuals; i++){
		taxa_individuals += vector_taxa[i];

		if(i%alignment_by_individuals == 0){
			fprintf(TaxaOut,"%d\n",taxa_individuals);
			taxa_individuals = 0;
		}
	}
}


void Threads::run()
{
	int i;
	int *id;

	for(i = 0; i < NUM_THREADS; i++){//Criando threads
		id = new int[1];
		id[0] = i;
		if ((i + 1) <= num_individuals)
			vector_thread.at(i) = thread( &Threads::threads_needlemanwunsch, this, (void*)id );
	}

	for(i = 0; i < NUM_THREADS; i++){//Esperando a thread terminar
		if((i+1) <= num_individuals)
			vector_thread.at(i).join();
	}
}


int Threads::vectors_malloc()
{
	query = (TypeQuery *) _aligned_malloc(sizeof(TypeQuery)*(alignment_by_individuals*TAMSEQ),64);
		if(!query){printf("ERROR: Alloc_query(size:%d)\n",  (TAMSEQ)); return -1;}
	individuals = (TypeIndividuals *) _aligned_malloc((sizeof(TypeIndividuals)*TAMSEQ*alignment_by_individuals*num_individuals),64);
		if(!individuals){printf("ERROR: Alloc_individuals(size:%u)\n",  (TAMSEQ*alignment_by_individuals*num_individuals)); return -1;}
	store_individuals = (TypeIndividuals *) _aligned_malloc((sizeof(TypeIndividuals)*(TAMSEQ/Byte_By_TwoBit)*alignment_by_individuals*num_individuals),64);
		if(!individuals){printf("ERROR: Alloc_store_individuals(size:%u)\n",  ((TAMSEQ/Byte_By_TwoBit)*alignment_by_individuals*num_individuals)); return -1;}
	mat_direction = (TypeMat_direction*) _aligned_malloc(sizeof(TypeMat_direction)*(TAMSEQ)*(TAMSEQ/Byte_By_TwoBit)*NUM_THREADS,64);
		if(!mat_direction){printf("ERROR: Alloc_mat_direction(size:%d)\n", (TAMSEQ*TAMSEQ)*NUM_THREADS); return -1;}

	vector_taxa = (int*) _aligned_malloc(sizeof(int)*alignment_by_individuals*num_individuals,64);
		if(!vector_taxa){printf("ERROR: Alloc_taxa(size:%d)\n", num_individuals); return -1;}
	score_vector = (int *) _aligned_malloc(sizeof(int)*(TAMSEQ+1)*NUM_THREADS,64);
		if(!score_vector){printf("ERROR: Alloc_score_vector(size:%d)\n",(TAMSEQ+1)*NUM_THREADS); return -1;}

	vector_thread.resize( NUM_THREADS );

return 0;
}


void Threads::read_input_individuals() {
	int i, k;

	fread(store_individuals, sizeof(TypeIndividuals), (TAMSEQ / Byte_By_TwoBit)*alignment_by_individuals*num_individuals, BD_nucleotideos);
	store_individuals[(TAMSEQ / 4)*alignment_by_individuals*num_individuals] = '\0';

	for (i = 0, k = 0; i < (TAMSEQ / Byte_By_TwoBit)*alignment_by_individuals*num_individuals; i++){

		individuals[k++] = (MASK_NCL1 & store_individuals[i]) + 48;
		individuals[k++] = ((MASK_NCL2 & store_individuals[i]) >> 2) + 48;
		individuals[k++] = ((MASK_NCL3 & store_individuals[i]) >> 4) + 48;
		individuals[k++] = ((MASK_NCL4 & store_individuals[i]) >> 6) + 48;
	}
	individuals[k] = '\0';
}


void Threads::read_input_query() {

	int j, k = 0;
	TypeQuery nucleotideo;

	fj(0, (TAMSEQ / Byte_By_TwoBit)*alignment_by_individuals*query_compare){
		fread(&nucleotideo, sizeof(TypeQuery), 1, BD_nucleotideos);

		if (j >= ((TAMSEQ / Byte_By_TwoBit)*alignment_by_individuals*(query_compare - 1))){
			query[k++] = (MASK_NCL1 & nucleotideo) + 48;
			query[k++] = ((MASK_NCL2 & nucleotideo) >> 2) + 48;
			query[k++] = ((MASK_NCL3 & nucleotideo) >> 4) + 48;
			query[k++] = ((MASK_NCL4 & nucleotideo) >> 6) + 48;
		}
	}
	query[k] = '\0';
}